home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / BARNET / COMPILER / SATHER / !Sather / Library / Graphs / sa / digraph < prev    next >
Text File  |  1996-07-13  |  9KB  |  263 lines

  1. ---------------------------> Sather 1.1 source file <--------------------------
  2. -- Author: Benedict A. Gomes <gomes@icsi.berkeley.edu>
  3. -- COPYRIGHT NOTICE: This code is provided WITHOUT ANY WARRANTY
  4. -- and is subject to the terms of the SATHER LIBRARY GENERAL PUBLIC
  5. -- LICENSE contained in the file: Sather/Doc/License of the
  6. -- Sather distribution. The license is also available from ICSI,
  7. -- 1947 Center St., Suite 600, Berkeley CA 94704, USA.
  8. -------------------------------------------------------------------
  9. class DIGRAPH < $DIGRAPH{INT} is
  10.    -- A default digraph implementation which uses integer nodes
  11.    include DIGRAPH{INT};
  12.    
  13.    create: SAME is
  14.       return create(#INT_STREAM(0));
  15.    end;
  16.    
  17. end;
  18. -------------------------------------------------------------------
  19. class DIGRAPH{NTP}  < $DIGRAPH{NTP} is
  20.    -- This is a directed graph which permits arbitrary nodes of type
  21.    -- NTP.  This is the default graph implementation. NTP is the node
  22.    -- type i.e the unique node index The actual nodes of the graph may
  23.    -- be supplied by the user of this class, during the add_node.  The
  24.    -- digraph is implemented by two hash mappings from nodes to
  25.    -- parents and nodes to outgoing. There is also a separate list of
  26.    -- nodes.
  27.  
  28.    private include COMPARE{NTP} elt_eq->node_equal;
  29.    include DIGRAPH_INCL{NTP};
  30.    
  31.    private attr node_generator: $SUCC_STREAM{NTP}; -- Generator of nodes
  32.    -- which is used by add_node. If a node generator is not provided
  33.    -- at creation time, then add_node cannot be used, since the graph
  34.    -- does not know how to create new unique nodes.
  35.    
  36.    private attr node_list: FLIST{NTP}; -- List of nodes in the graph
  37.    private attr incoming_map: FMULTIMAP{NTP,NTP};
  38.    private attr outgoing_map: FMULTIMAP{NTP,NTP};
  39.    -- Keep both around since it is quite expensive to derive one
  40.    -- from the other.
  41.    
  42.    create: SAME is 
  43.       -- Create a new digraph and return it. Since a node 
  44.       -- generator is not specified, it will not be possible
  45.       -- to call the "add_node:NTP" function, since the graph
  46.       -- will not know how to create new unique nodes.
  47.       -- All the data structures can be initialized with void
  48.       res ::= new;
  49.       res.incoming_map := #FMULTIMAP{NTP,NTP};
  50.       res.outgoing_map := #FMULTIMAP{NTP,NTP};
  51.       res.node_list := #;
  52.       return(res) 
  53.    end;
  54.  
  55.    create(node_gen: $SUCC_STREAM{NTP}): SAME pre ~void(node_gen) is
  56.       -- Create a new digraph. Store "node_gen" as a generator
  57.       -- of nodes, so that when "add_node: NTP" is called it
  58.       -- can generate unique new nodes. 
  59.       res: SAME := create;
  60.       res.node_generator := node_gen;
  61.       return res;
  62.    end;
  63.    
  64.    -- ------------------- Initialization ------------------
  65.    add_node: NTP is
  66.       -- Add a new node and return the index
  67.       if void(node_generator) then
  68.      raise #GRAPH_EXC(self,"add_node",self,
  69.               "Cannot call add_node: NTP on this graph."
  70.               " No node generator was provided");
  71.       else
  72.      -- Get the next unique node
  73.      n: NTP := node_generator.next; 
  74.      -- If it is really unique, add it to the list
  75.      assert ~has_node(n);
  76.      node_list := node_list.push(n);  
  77.      return n;
  78.       end;
  79.    end;
  80.    
  81.    add_node(n: NTP): NTP is
  82.       -- Add the node "n". In this kind of hash digraph, the node
  83.       -- index returned is guaranteed to be the same as the node
  84.       -- "n". Note that this is not generally true for graphs
  85.       if ~has_node(n) then node_list := node_list.push(n); end;
  86.       return n;
  87.    end;
  88.    
  89.    
  90.    add_node(n: NTP) is
  91.       -- Short hand for "add_node(n:NTP): NTP" that is only valid
  92.       -- for this sort of graph, where the user specifies the node
  93.       -- type. 
  94.       if ~has_node(n) then node_list := node_list.push(n); end;
  95.    end;
  96.  
  97.    connect(e: DIEDGE{NTP}) is
  98.       -- Connect source to target. No change if the edge already exists
  99.       -- Add the nodes if they do not exist
  100.       s ::= e.first; t ::= e.second;
  101.       if has_edge(#DIEDGE{NTP}(s,t)) then return; end;
  102.       if ~has_node(s) then add_node(s) end;
  103.       if ~has_node(t) then add_node(t) end;
  104.       outgoing_map := outgoing_map.insert(s,t);
  105.       incoming_map := incoming_map.insert(t,s);
  106.    end;
  107.    
  108.    -- ------------------- Removal -------------------------
  109.    delete_node(n: NTP) is
  110.       -- Delete a node from the graph, and all its accompanying edges
  111.       node_list := node_list.delete_elt(n);
  112.       incoming_map := incoming_map.delete_all(n);
  113.       outgoing_map := outgoing_map.delete_all(n);
  114.    end;
  115.    
  116.    disconnect(e: DIEDGE{NTP}) is
  117.       -- Deletes the edge "e". 
  118.       dest ::= e.second; src ::= e.first;
  119.       incoming_map := incoming_map.delete(dest,src);
  120.       outgoing_map := outgoing_map.delete(src,dest);
  121.    end;
  122.  
  123.    -- ------------------- Query --------------------------
  124.    has_node(n: NTP): BOOL is return node_list.has(n) end;
  125.    
  126.    has_edge(e: DIEDGE{NTP}): BOOL is
  127.       s ::= e.first; t ::= e.second;
  128.       if ~has_node(s) or ~has_node(t) then return false
  129.       else return incoming_map.has_pair(t,s);   end;
  130.    end;
  131.    
  132.    -- ------------------- Measurement ---------------------
  133.    n_nodes: INT is return node_list.size end;
  134.  
  135.    n_neighbors(n: NTP): INT pre has_node(n) is 
  136.       -- Returns the number of neighbors of "n"
  137.       -- (nodes are only counted once)
  138.       i: FLIST{NTP} := incoming_map.danger_multi_get(n);
  139.       o: FLIST{NTP} := incoming_map.danger_multi_get(n);
  140.       if i.size = 0 then return o.size 
  141.       elsif o.size = 0 then return i.size
  142.       else return i.union(o).size end;
  143.    end;
  144.    
  145.    n_incoming(n: NTP): INT pre has_node(n) is
  146.       -- Number of incoming edges from node "n"
  147.       return(incoming_map.n_targets(n));
  148.    end;
  149.  
  150.    n_outgoing(n: NTP): INT pre has_node(n) is
  151.       -- Number of outgoing edges from node "n"
  152.       return(outgoing_map.n_targets(n));
  153.    end;
  154.  
  155.    n_edges: INT is
  156.       -- Returns the number of edges in the graph, making sure
  157.       -- each edge is only counted once
  158.       res ::= 0;
  159.       loop n ::= node!; res := res+n_incoming(n); end;
  160.       return res;
  161.    end;
  162.  
  163.    -- ------------------- Cursor --------------------------
  164.    node!: NTP is loop yield node_list.elt! end; end;
  165.  
  166.    incoming!(once n: NTP): NTP pre has_node(n) is  
  167.       loop yield incoming_map.target!(n) end;
  168.    end;
  169.    
  170.    outgoing!(once n: NTP): NTP pre has_node(n) is  
  171.       loop yield outgoing_map.target!(n) end;
  172.    end;
  173.    
  174.    edge!: DIEDGE{NTP} is 
  175.       -- Return all edges in the graph
  176.       loop n ::= node!;
  177.      loop inc ::= incoming!(n); yield #DIEDGE{NTP}(inc,n); end;
  178.      -- loop outg ::= outgoing!(n); yield #DIEDGE{NTP}(n,outg); end;
  179.       end;
  180.    end;
  181.  
  182.    -- ------------------  COMPARING ---------------------------------
  183.    is_identical(g: SAME): BOOL is
  184.       -- Check whether the two graphs have the same nodes, edges in
  185.       -- the same order
  186.       if g.n_nodes /= n_nodes then return false end;
  187.       loop  if ~node_equal(node!,g.node!) then return false end end;
  188.       loop n::= node!;
  189.      if ~incoming_map.get_all(n).equals(g.incoming_map.get_all(n)) then 
  190.         return false 
  191.      elsif ~outgoing_map.get_all(n).equals(g.outgoing_map.get_all(n)) then 
  192.         return false 
  193.      end;
  194.       end;
  195.       return true
  196.    end;
  197.  
  198.    -- Some convenient calls into algorithm classes that are not required 
  199.    -- by the abstraction
  200.    source!: NTP is
  201.       -- Yield all the source nodes with n_incoming = 0 in self
  202.       loop yield DIGRAPH_ALG{NTP,SAME}::source!(self) end;
  203.    end;
  204.       
  205.    sink!: NTP is
  206.       -- Yield all the sink nodes (with n_outgoing = 0) in self
  207.       loop yield DIGRAPH_ALG{NTP,SAME}::sink!(self) end;
  208.    end;
  209.    
  210.    bf!(once n: NTP): NTP is 
  211.       -- Yield all nodes in breadth first order
  212.       loop yield DIGRAPH_ALG{NTP,SAME}::bf!(self,n) end; 
  213.    end;
  214.    
  215.    df!(once n: NTP): NTP is 
  216.       -- Yield all nodes in depth first order
  217.       loop yield DIGRAPH_ALG{NTP,SAME}::df!(self,n) end; 
  218.    end;
  219.    
  220.    topo_order!: NTP is 
  221.       -- Yield the nodes of self in some topologically sorted orer
  222.       loop yield DIGRAPH_ALG{NTP,SAME}::topo_order!(self) end; 
  223.    end;
  224.    
  225.    layer!: SET{NTP} is 
  226.       -- Peel off successive layers from the graph, starting with the
  227.       -- root set. Stop when no more roots (nodes with no incoming edges)
  228.       -- can be found.
  229.       loop yield DIGRAPH_ALG{NTP,SAME}::layer!(self) end; 
  230.    end;
  231.  
  232.    is_topo_order(n: $ARR{NTP}):BOOL is 
  233.       -- Return true if the nodes in "n" do not violate the precedence
  234.       -- relations expressed by the graph "self"
  235.       return DIGRAPH_ALG{NTP,SAME}::is_topo_order(self,n) 
  236.    end;
  237.  
  238.  
  239.    private check_node(n: NTP,routine_name: STR): BOOL is
  240.       if has_node(n) then return true 
  241.       else 
  242.      #ERR+routine_name+" received a node not in the graph\n";
  243.      return false;
  244.       end;
  245.    end;
  246.  
  247.    
  248. -- Adaptors
  249. --   reverse_graph: DIGRAPH_REVERSE_VIEW{NTP} is
  250. --      return(#DIGRAPH_REVERSE_VIEW{NTP}(self));
  251. --   end;
  252.    
  253. --   subgraph: DIGRAPH_SUBGRAPH_VIEW{NTP} is
  254. --      return(#DIGRAPH_SUBGRAPH_VIEW{NTP}(self));
  255. --   end;
  256.    
  257. --   undirected: DIGRAPH_UNDIRECTED_VIEW{NTP} is
  258. --      return(#DIGRAPH_UNDIRECTED_VIEW{NTP}(self));
  259. --   end;
  260.  
  261. end; -- class DIGRAPH{NTP}
  262. -------------------------------------------------------------------
  263.